﻿// Allows a component to render itself as HTML
define([
'Xjs/core/util',
'Xjs/core/builder',
'Xjs/core/dom',
// Ensure the creation of the global Xjs
'Xjs/app'
],
function (util, builder, dom) {
    'use strict';

    var type = 'htmlRenderer', // Use the type registration to avoid recreating the type
    HtmlRenderer = Xjs.getType(type);

    if (HtmlRenderer) { // It has been already loaded
        return HtmlRenderer;
    }

    // Renders the html from a component
    HtmlRenderer = util.define({

        type: type, // Set the type

        initialize: function (conf) {

            conf = conf || {};

            var tag = conf.tag || this.tag,
            attributes = conf.attributes || {},
            theme = conf.theme,
            hidden = conf.hidden || this.hidden,
            visible = conf.visible || this.visible,
            border = conf.border || this.border,
            cls = conf.cls || this.cls || 'w-' + this.type, // The classes listed here replace all the default classes of the control
            style = util.parseStyle(attributes.style); // Convert the styles to object

            if (this.id) {
                attributes.id = this.id;
            }

            if (attributes.cls) {
                attributes.cls = cls + ' ' + attributes.cls;
            }
            else { // Map the class to the type
                attributes.cls = cls;
            }

            if (hidden) { // Set the control as initially hidden
                style.display = 'none';
            }

            if (conf.style) { // Add any style provided in the configuration
                util.augment(style, conf.style);
            }

            if (visible === false) { // Set the control as initially invisible
                style.visibility = 'hidden';
            }

            if (border) {
                attributes.cls = attributes.cls ? attributes.cls + ' w-border' : ' w-border';
            }

            // Convert back the style to string if there are any style
            if (!util.isEmpty(style)) {
                attributes.style = util.styleToString(style);
            }

            // Create the builder to be used to build the html to render this control. // TODO: Is it required only to render the control (can it be deleted after render?)
            this.builder = builder.createNode(tag).addAttributes(attributes).setTheme(theme);
        },

        // Build the HTML to render the component
        build: function () {

            this.builder.clear();

            if (this.onBeforeBuild) {
                this.onBeforeBuild(); // Allow to add other components as needed
            }

            if (this.callHandlers) {
                this.callHandlers('onBeforeBuild'); // Call any handler registered for this event
            }

            if (this.children) {
                this.children.forEach(function (child) {
                    this.builder.addNode(child.build());
                }, this);
            }

            return this.builder;
        },

        // Emits the html markup for the control
        render: function () {
            this.build();
            return this.builder.render();
        },

        // Renders the control to a dom node
        appendTo: function (el) {

            if (!util.isDomNode(el)) {
                throw 'Must be a dom node';
            }

            if (this.onBeforeAppend) {
                this.onBeforeAppend.call(this);
            }

            var html = this.render();
            dom.append(el, html);

            this.onRender();
        }
    });

    Xjs.registerType(HtmlRenderer);

    return HtmlRenderer;
});